// const static 在类内可以定义成整数的形式
//
#include <iostream>
#include <sys/socket.h>
#include <stdio.h>
#include <cstring>
#include <string>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <functional>
namespace Server
{
    using namespace std;
    enum
    {
        USAGE_ERROR = 1,
        SOCK_ERROR,
        BIND_ERROR,
        OPEN_ERROR,
        POPEN_ERROR
    };
    // typedef function<void(string,string,string)> func_t;
    static const string defaultIP = "0.0.0.0";
    using func_t = function<void(int,string, uint16_t, string)>;

    class udpserver
    {
        const static int nummessage = 1024;

    public:
        udpserver(func_t func, const uint16_t& port, const string &ip = defaultIP)
            : _callback(func), _port(port), _ip(ip), _sockfd(-1)
        {
        }
       void initServer()
        {
            // 1.创建套接字
            _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
            if (_sockfd == -1)
            {
                // Socket报错
                cerr << "socket error :" << errno << " : " << strerror(errno) << endl;
                exit(SOCK_ERROR);
            }
            cout<<"socket seccess :"<<_sockfd<<endl;
            // 2.绑定端口号
            // 服务器要明确的端口号，不能随意改变
            struct sockaddr_in local; // 在用户栈上面首先进行操作
            bzero(&local, sizeof(local));
            local.sin_family = AF_INET;
            local.sin_port = htons(_port);
            local.sin_addr.s_addr = inet_addr(_ip.c_str());   //完成两个操作 string--->uint32_t   大小端转换htonl() ->inet_addr
            //local.sin_addr.s_addr = inet_addr(INADDR_ANY); //  一般不明确的绑定某个独立的ip，让上层服务器可以接受来自任意ip上传的信息
            // 一般都是绑定任意地址，服务器的真实写法
            int n = bind(_sockfd, (struct sockaddr *)&local, sizeof(local));
            if (n == -1)
            {
                cerr << "bind error :" << errno << " : " << strerror(errno) << endl;
                exit(BIND_ERROR);
            }
            cout<<"bind success"<<endl;
            // UDP的预备工作完成
        }
        void startServer()
        {
            // 服务器的本质其实是一个死循环
            char buffer[nummessage];
            for (;;)
            {
                // 读取数据
                struct sockaddr_in destnation; // 这是一个输入输出型参数，用来接受对方的ip和port
                socklen_t len = sizeof(destnation);
                ssize_t num = recvfrom(_sockfd, buffer, nummessage, 0, (struct sockaddr *)&destnation, &len);
                if (num > 0)
                {

                    buffer[num] = 0; // 将最后一个置为/0
                    // 获取数据，并且获取是谁发的数据
                    string clientip = inet_ntoa(destnation.sin_addr);
                    uint16_t clientport = ntohs(destnation.sin_port);
                    string message = buffer;
                    cout << clientip << "[" << clientport << "]" << message << endl;
                    // 对读取到的数据进行处理
                    _callback(_sockfd, clientip, clientport, message);
                }
            }
        }
        ~udpserver()
        {
        }
    private:
        uint16_t _port;  // 端口号
        std::string _ip; // ip地址,实际上一款网络服务器，不建议指明一个IP
        int _sockfd;
        func_t _callback; // 业务函数
    };
}